﻿using Gargoyle.Roton;
using System;
using System.Collections.Generic;
using System.Text;

namespace Gargoyle.ZZT
{
    public sealed class Thing
    {
        private Heap heap;
        private Pointer pointer;

        public Int16 Cycle 
        {
            get { return pointer.GetInt16(6); }
            set { pointer.SetInt16(6, value); }
        }
        public Int16 Follower
        {
            get { return pointer.GetInt16(11); }
            set { pointer.SetInt16(11, value); }
        }
        public Int16 Instruction
        {
            get { return pointer.GetInt16(21); }
            set { pointer.SetInt16(21, value); }
        }
        public Pointer InstructionReference
        {
            get { return pointer.GetRelativePointer(21); }
        }
        public Int16 Leader
        {
            get { return pointer.GetInt16(13); }
            set { pointer.SetInt16(13, value); }
        }
        public Int16 Length
        {
            get { return pointer.GetInt16(23); }
            set { pointer.SetInt16(23, value); }
        }
        public Location Location
        {
            get 
            {
                return new Location(pointer.GetRelativePointer(0)); 
            }
            set
            {
                pointer[0] = value.X;
                pointer[1] = value.Y;
            }
        }
        public byte P1
        {
            get { return pointer[8]; }
            set { pointer[8] = value; }
        }
        public byte P2
        {
            get { return pointer[9]; }
            set { pointer[9] = value; }
        }
        public byte P3
        {
            get { return pointer[10]; }
            set { pointer[10] = value; }
        }
        public Int32 Pointer
        {
            get { return pointer.GetInt32(17); }
            set { pointer.SetInt32(17, value); }
        }
        public Tile UnderTile
        {
            get { return new Tile(pointer.GetRelativePointer(15)); }
            set
            {
                pointer[15] = value.Element;
                pointer[16] = value.Color;
            }
        }
        public Vector Vector
        {
            get { return new Vector(pointer.GetRelativePointer(2)); }
            set
            {
                pointer.SetInt16(2, value.X);
                pointer.SetInt16(4, value.Y);
            }
        }

        public Thing(Heap heap)
        {
            this.heap = heap;
            pointer = new Pointer(new byte[25]);
        }

        public Thing(Heap heap, Memory memory)
        {
            this.heap = heap;
            pointer = memory.GetRelativePointer(0);
        }

        public Thing(Heap heap, Memory memory, int offset)
        {
            this.heap = heap;
            pointer = memory.GetRelativePointer(offset);
        }

        public Thing(Heap heap, Pointer pointer)
        {
            this.heap = heap;
            this.pointer = pointer;
        }

        public Thing Clone()
        {
            byte[] newmem = new byte[25];
            for (int i = 0; i < 25; i++)
            {
                newmem[i] = pointer[i];
            }

            Thing result = new Thing(heap, new Memory(newmem));
            result.Code = this.Code;

            return result;
        }

        public ByteString Code
        {
            get
            {
                int ptr = Pointer;
                if (ptr != 0)
                    return heap[ptr];
                else
                    return null;
            }
            set
            {
                Pointer = heap.Allocate(value);
            }
        }

        public void CopyFrom(Thing source)
        {
            Cycle = source.Cycle;
            Follower = source.Follower;
            Instruction = source.Instruction;
            Leader = source.Leader;
            Length = source.Length;
            Location.CopyFrom(source.Location);
            P1 = source.P1;
            P2 = source.P2;
            P3 = source.P3;
            Pointer = source.Pointer;
            UnderTile.CopyFrom(source.UnderTile);
            Vector.CopyFrom(source.Vector);
        }

        public override string ToString()
        {
            return "Thing (X=" + Location.X + ", Y=" + Location.Y + ")";
        }

        public byte X
        {
            get
            {
                return pointer[0];
            }
            set
            {
                pointer[0] = value;
            }
        }

        public Int16 XStep
        {
            get
            {
                return pointer.GetInt16(2);
            }
            set
            {
                pointer.SetInt16(2, value);
            }
        }

        public byte Y
        {
            get
            {
                return pointer[1];
            }
            set
            {
                pointer[1] = value;
            }
        }

        public Int16 YStep
        {
            get
            {
                return pointer.GetInt16(4);
            }
            set
            {
                pointer.SetInt16(4, value);
            }
        }
    }
}
